package com.jse.api;

import java.net.http.HttpClient.Version;
import java.net.http.HttpResponse;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;

import com.jse.Fs;
import com.jse.Http;
import com.jse.Jse;
import com.jse.Times;
import com.jse.json.JsonObject;
import com.jse.json.XML;

/**
 * 提供了与阿里云对象存储服务（OSS）交互的方法。
 */
public class Oss {

    /**
     * 上传文件到 OSS。
     * 
     * @param map 包含上传配置的 Map，可以包含以下键：
     *            <ul>
     *              <li>bucket (String): 桶名称。默认从配置中读取。</li>
     *              <li>path (String): 文件路径。默认为 "upload/" 加上文件名。</li>
     *              <li>file (String): 本地文件路径。</li>
     *              <li>key (String): 阿里云 Access Key ID。默认从配置中读取。</li>
     *              <li>secret (String): 阿里云 Access Key Secret。默认从配置中读取。</li>
     *              <li>domain (String): OSS 域名。默认从配置中读取。</li>
     *            </ul>
     * @return 上传结果的字符串表示形式
     * @throws Exception 如果发生异常
     */
    public static String upload(Map<String, Object> map) {
        String bucket = map.containsKey("bucket") ? map.get("bucket").toString()
                : Jse.conf.getString("ali.oss.bucket");
        String file = map.get("file").toString();
        var f = Path.of(file);
        String path = map.containsKey("path") ? map.get("path").toString() : "upload/" + f.getFileName().toString();
        String accessKeyId = map.containsKey("key") ? map.get("key").toString()
                : Jse.conf.getString("ali.key");
        String accessKeySecret = map.containsKey("secret") ? map.get("secret").toString()
                : Jse.conf.getString("ali.secret");
        String domain = map.containsKey("domain") ? map.get("domain").toString()
                : Jse.conf.getString("ali.oss.domain");
        String url = "http://" + domain + "/" + path;
        Map<String, String> header = new HashMap<>();
        String ds = Times.gmt();
        header.put("Date", ds);
        byte[] body = Fs.readAllBytes(f);
        String suffix = Fs.suffix(file);
        String contentType = Fs.mimeType(suffix, "");
        header.put("Content-Type", contentType);
        String str = "PUT\n\n" + contentType + "\n" + ds + "\n/" + bucket + "/" + path;
        String Authorization = "OSS " + accessKeyId + ":";
        String sign = Ali.hmacSHA1Signature(accessKeySecret, str);
        header.put("Authorization", Authorization + sign);
        try {
            return Http.send(Version.HTTP_1_1, "PUT", url, body, 60000, header, false, null).toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 列出 OSS 桶中的对象。
     * 
     * @param map 包含列出配置的 Map，可以包含以下键：
     *            <ul>
     *              <li>bucket (String): 桶名称。默认从配置中读取。</li>
     *              <li>path (String): 查询路径。默认为空。</li>
     *              <li>key (String): 阿里云 Access Key ID。默认从配置中读取。</li>
     *              <li>secret (String): 阿里云 Access Key Secret。默认从配置中读取。</li>
     *              <li>domain (String): OSS 域名。默认从配置中读取。</li>
     *            </ul>
     * @return 列出结果的 JSON 对象
     */
    public static JsonObject list(Map<String, Object> map) {
        String bucket = map.containsKey("bucket") ? map.get("bucket").toString()
                : Jse.conf.getString("ali.oss.bucket");
        String accessKeyId = map.containsKey("key") ? map.get("key").toString()
                : Jse.conf.getString("ali.key");
        String accessKeySecret = map.containsKey("secret") ? map.get("secret").toString()
                : Jse.conf.getString("ali.secret");
        String path = map.containsKey("path") ? map.get("path").toString() : "";
        String domain = map.containsKey("domain") ? map.get("domain").toString()
                : Jse.conf.getString("ali.oss.domain");
        String url = "http://" + domain + "/" + path;
        Map<String, String> header = new HashMap<>();
        String ds = Times.gmt();
        header.put("Date", ds);
        String contentType = "";
        header.put("Content-Type", contentType);
        String str = "GET\n\n" + contentType + "\n" + ds + "\n/" + bucket + "/";
        String Authorization = "OSS " + accessKeyId + ":";
        String sign = Ali.hmacSHA1Signature(accessKeySecret, str);
        header.put("Authorization", Authorization + sign);
        try {
            Object o = Http.send(Version.HTTP_1_1, "GET", url, "", 60000, header, false, "");
            if (o instanceof HttpResponse<?> resp) {
                return XML.toJSONObject(resp.body().toString());
            }
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 删除 OSS 中的对象或空文件夹。
     * 
     * @param map 包含删除配置的 Map，可以包含以下键：
     *            <ul>
     *              <li>bucket (String): 桶名称。默认从配置中读取。</li>
     *              <li>path (String): 要删除的对象路径。如果以斜杠结尾则视为文件夹。默认为空。</li>
     *              <li>key (String): 阿里云 Access Key ID。默认从配置中读取。</li>
     *              <li>secret (String): 阿里云 Access Key Secret。默认从配置中读取。</li>
     *              <li>domain (String): OSS 域名。默认从配置中读取。</li>
     *            </ul>
     * @return 删除操作的结果字符串
     */
    public static String del(Map<String, Object> map) {
        String bucket = map.containsKey("bucket") ? map.get("bucket").toString()
                : Jse.conf.getString("ali.oss.bucket");
        String accessKeyId = map.containsKey("key") ? map.get("key").toString()
                : Jse.conf.getString("ali.key");
        String accessKeySecret = map.containsKey("secret") ? map.get("secret").toString()
                : Jse.conf.getString("ali.secret");
        String path = map.containsKey("path") ? map.get("path").toString() : "";
        String domain = map.containsKey("domain") ? map.get("domain").toString()
                : Jse.conf.getString("ali.oss.domain");
        String url = "http://" + domain + "/" + path;
        Map<String, String> header = new HashMap<>();
        String ds = Times.gmt();
        header.put("Date", ds);
        String contentType = "";
        header.put("Content-Type", contentType);
        String str = "DELETE\n\n" + contentType + "\n" + ds + "\n/" + bucket + "/" + path;
        String Authorization = "OSS " + accessKeyId + ":";
        String sign = Ali.hmacSHA1Signature(accessKeySecret, str);
        header.put("Authorization", Authorization + sign);
        try {
            Object o = Http.send(Version.HTTP_1_1, "DELETE", url, "", 60000, header, false, "");
            return o.toString();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 主方法用于测试上传、列出和删除操作。
     * 
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        // 示例：上传文件
//        upload(Map.of("bucket", "iepsy", "path", "upload/1.txt", "file", "d:/1.txt",
//                "key", "你的id", "secret", "你的secret",
//                "domain", "iepsy.oss-cn-beijing.aliyuncs.com"));
        
        // 示例：列出对象
        JsonObject a = list(Map.of("bucket", "iepsy", "path", "?list-type=2&max-keys=1000",
                "key", "你的id", "secret", "你的secret",
                "domain", "iepsy.oss-cn-beijing.aliyuncs.com"));
        System.out.println(a.getJSONObject("ListBucketResult").get("CommonPrefixes").getClass().getName());
        System.out.println(a.getJSONObject("ListBucketResult").get("Contents").getClass().getName());

        // 示例：删除对象
//        String a = del(Map.of("bucket", "iepsy", "path", "upload/2.txt",
//                "key", "LTAI8MDgUrXvLBpl", "secret", "OlEapJaG8KtKjqqPpLadX2b3zQ3p94",
//                "domain", "iepsy.oss-cn-beijing.aliyuncs.com"));
    }
}